#include <string.h>
#include <iostream>
using std::cout;
using std::endl;
using std::ostream;

class CowString{
public:
    CowString()
    : _pstr(malloc())
    { 
        cout << "CowString()" << endl;
        initRefcount();
    }

    CowString(const char * pstr);
    CowString(const CowString & rhs);
    CowString & operator=(const CowString & rhs);
    ~CowString();

    const char * c_str() const{return _pstr;}
    int use_count(){ return *(int*)(_pstr - kRefcountLength); }
    int size() const{ return strlen(_pstr); }
    
    char & operator[](size_t idx);

    friend ostream & operator<<(ostream & os,const CowString & rhs);
private:
    char * malloc(const char * pstr = nullptr)
    {
        if(pstr){
            return new char[strlen(pstr) + kRefcountLength + 1]() + kRefcountLength;
        }else{
            return new char[1 + kRefcountLength]() + kRefcountLength;
        }
    }

    void release(){
        decreaseRefcount();
        if(use_count() == 0){
            delete [] (_pstr - kRefcountLength);
            _pstr = nullptr;
            cout << ">> delete heap" << endl;
        }
    }


    void initRefcount(){
        *(int*)(_pstr - kRefcountLength) = 1;
    }

    void increaseRefcount(){
       ++*(int*)(_pstr - kRefcountLength);
    }

    void decreaseRefcount(){
       --*(int*)(_pstr - kRefcountLength);
    }

    char * _pstr;
    static const int kRefcountLength = 4;
};
/* const int CowString::kRefcountLength = 4; */

ostream & operator<<(ostream & os,const CowString & rhs){
    os << rhs._pstr;
    return os;
}

char & CowString::operator[](size_t idx){
    if(idx >= 0 && idx < size()){
        if(use_count() > 1){
            //1.原来的引用计数减1
            decreaseRefcount();
            //2.进行深拷贝
            char * ptmp = malloc(_pstr);
            strcpy(ptmp,_pstr);
            //3.改变指向
            _pstr = ptmp;
            initRefcount();
        }
        return _pstr[idx];
    }else{
        cout << "访问越界" << endl;
        static char nullchar = '\0';
        return nullchar;
    }
}

CowString::~CowString(){
    cout << "~CowString()" << endl;
    release();
}

CowString::CowString(const CowString & rhs)
: _pstr(rhs._pstr)//浅拷贝
{
    increaseRefcount();
    cout << "CowString(const CowString &)" << endl;
}

CowString::CowString(const char * pstr)
: _pstr(malloc(pstr))
{
    cout << "cowString(const char *)" << endl;
    strcpy(_pstr,pstr);
    initRefcount();
}
CowString & CowString::operator=(const CowString & rhs){
    if(this!=&rhs){//1.考虑自复制
       release();//2.判断之后回收左操作数的空间
       _pstr = rhs._pstr;//3.浅拷贝
       increaseRefcount();//4.引用计数加一
    }
    return *this;//5.
}

void test0(){
    CowString str;
    cout <<  str.use_count() << endl;
    CowString str2 = str;
    cout << "str:" << str << endl;
    cout << "str2:" << str2 << endl;
    cout <<  str.use_count() << endl;
    cout <<  str2.use_count() << endl;

    cout << "###############" << endl;
    CowString str3("hello");
    cout <<  str3.use_count() << endl;
    CowString str4 =str3;
    cout << "str3:" << str3 << endl;
    cout << "str4:" << str4 << endl;
    /* cout <<  str.use_count() << endl; */
    /* cout <<  str2.use_count() << endl; */
    cout <<  str3.use_count() << endl;
    cout <<  str4.use_count() << endl;
    cout << "###############" << endl;
    str2 = str3;
    cout << "str2:" << str2 << endl;
    cout <<  str.use_count() << endl;
    cout <<  str2.use_count() << endl;
    cout <<  str3.use_count() << endl;
    cout <<  str4.use_count() << endl;
    cout << "###############" << endl;
    str2[0] = 'x';
    cout << "str:" << str << endl;
    cout << "str2:" << str2 << endl;
    cout << "str3:" << str3 << endl;
    cout << "str4:" << str4 << endl;
    cout <<  str.use_count() << endl;
    cout <<  str2.use_count() << endl;
    cout <<  str3.use_count() << endl;
    cout <<  str4.use_count() << endl;
    cout << "###############" << endl;
    cout << "执行读操作" << endl;
    cout << str3[0] << endl;
    cout << "str2:" << str2 << endl;
    cout << "str3:" << str3 << endl;
    cout << "str4:" << str4 << endl;
    cout <<  str2.use_count() << endl;
    cout <<  str3.use_count() << endl;
    cout <<  str4.use_count() << endl;



}

int main(void){
    test0();
    return 0;
}
